(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){let c = 'function' === typeof require && require; if(!f && c){return c(i,!0)}if(u){return u(i,!0)}let a = new Error('Cannot find module \'' + i + '\''); throw a.code = 'MODULE_NOT_FOUND',a}let p = n[i] = {exports:{}}; e[i][0].call(p.exports,function(r){let n = e[i][1][r]; return o(n || r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u = 'function' === typeof require && require,i = 0; i < t.length; i++){o(t[i])}return o}return r})()({1:[function(require,module,exports){
  /* MIT license */
  /* eslint-disable no-mixed-operators */
  const cssKeywords = require('color-name')

  // NOTE: conversions should only return primitive values (i.e. arrays, or
  //       values that give correct `typeof` results).
  //       do not use box values types (i.e. Number(), String(), etc.)

  const reverseKeywords = {}
  for (const key of Object.keys(cssKeywords)) {
    reverseKeywords[cssKeywords[key]] = key
  }

  const convert = {
    rgb: {channels: 3, labels: 'rgb'},
    hsl: {channels: 3, labels: 'hsl'},
    hsv: {channels: 3, labels: 'hsv'},
    hwb: {channels: 3, labels: 'hwb'},
    cmyk: {channels: 4, labels: 'cmyk'},
    xyz: {channels: 3, labels: 'xyz'},
    lab: {channels: 3, labels: 'lab'},
    lch: {channels: 3, labels: 'lch'},
    hex: {channels: 1, labels: ['hex']},
    keyword: {channels: 1, labels: ['keyword']},
    ansi16: {channels: 1, labels: ['ansi16']},
    ansi256: {channels: 1, labels: ['ansi256']},
    hcg: {channels: 3, labels: ['h', 'c', 'g']},
    apple: {channels: 3, labels: ['r16', 'g16', 'b16']},
    gray: {channels: 1, labels: ['gray']}
  }

  module.exports = convert

  // Hide .channels and .labels properties
  for (const model of Object.keys(convert)) {
    if (!('channels' in convert[model])) {
      throw new Error('missing channels property: ' + model)
    }

    if (!('labels' in convert[model])) {
      throw new Error('missing channel labels property: ' + model)
    }

    if (convert[model].labels.length !== convert[model].channels) {
      throw new Error('channel and label counts mismatch: ' + model)
    }

    const {channels, labels} = convert[model]
    delete convert[model].channels
    delete convert[model].labels
    Object.defineProperty(convert[model], 'channels', {value: channels})
    Object.defineProperty(convert[model], 'labels', {value: labels})
  }

  convert.rgb.hsl = function (rgb) {
    const r = rgb[0] / 255
    const g = rgb[1] / 255
    const b = rgb[2] / 255
    const min = Math.min(r, g, b)
    const max = Math.max(r, g, b)
    const delta = max - min
    let h
    let s

    if (max === min) {
      h = 0
    } else if (r === max) {
      h = (g - b) / delta
    } else if (g === max) {
      h = 2 + (b - r) / delta
    } else if (b === max) {
      h = 4 + (r - g) / delta
    }

    h = Math.min(h * 60, 360)

    if (h < 0) {
      h += 360
    }

    const l = (min + max) / 2

    if (max === min) {
      s = 0
    } else if (l <= 0.5) {
      s = delta / (max + min)
    } else {
      s = delta / (2 - max - min)
    }

    return [h, s * 100, l * 100]
  }

  convert.rgb.hsv = function (rgb) {
    let rdif
    let gdif
    let bdif
    let h
    let s

    const r = rgb[0] / 255
    const g = rgb[1] / 255
    const b = rgb[2] / 255
    const v = Math.max(r, g, b)
    const diff = v - Math.min(r, g, b)
    const diffc = function (c) {
      return (v - c) / 6 / diff + 1 / 2
    }

    if (diff === 0) {
      h = 0
      s = 0
    } else {
      s = diff / v
      rdif = diffc(r)
      gdif = diffc(g)
      bdif = diffc(b)

      if (r === v) {
        h = bdif - gdif
      } else if (g === v) {
        h = (1 / 3) + rdif - bdif
      } else if (b === v) {
        h = (2 / 3) + gdif - rdif
      }

      if (h < 0) {
        h += 1
      } else if (h > 1) {
        h -= 1
      }
    }

    return [
      h * 360,
      s * 100,
      v * 100
    ]
  }

  convert.rgb.hwb = function (rgb) {
    const r = rgb[0]
    const g = rgb[1]
    let b = rgb[2]
    const h = convert.rgb.hsl(rgb)[0]
    const w = 1 / 255 * Math.min(r, Math.min(g, b))

    b = 1 - 1 / 255 * Math.max(r, Math.max(g, b))

    return [h, w * 100, b * 100]
  }

  convert.rgb.cmyk = function (rgb) {
    const r = rgb[0] / 255
    const g = rgb[1] / 255
    const b = rgb[2] / 255

    const k = Math.min(1 - r, 1 - g, 1 - b)
    const c = (1 - r - k) / (1 - k) || 0
    const m = (1 - g - k) / (1 - k) || 0
    const y = (1 - b - k) / (1 - k) || 0

    return [c * 100, m * 100, y * 100, k * 100]
  }

  function comparativeDistance(x, y) {
    /*
        See https://en.m.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance
      */
    return (
      ((x[0] - y[0]) ** 2) +
        ((x[1] - y[1]) ** 2) +
        ((x[2] - y[2]) ** 2)
    )
  }

  convert.rgb.keyword = function (rgb) {
    const reversed = reverseKeywords[rgb]
    if (reversed) {
      return reversed
    }

    let currentClosestDistance = Infinity
    let currentClosestKeyword

    for (const keyword of Object.keys(cssKeywords)) {
      const value = cssKeywords[keyword]

      // Compute comparative distance
      const distance = comparativeDistance(rgb, value)

      // Check if its less, if so set as closest
      if (distance < currentClosestDistance) {
        currentClosestDistance = distance
        currentClosestKeyword = keyword
      }
    }

    return currentClosestKeyword
  }

  convert.keyword.rgb = function (keyword) {
    return cssKeywords[keyword]
  }

  convert.rgb.xyz = function (rgb) {
    let r = rgb[0] / 255
    let g = rgb[1] / 255
    let b = rgb[2] / 255

    // Assume sRGB
    r = r > 0.04045 ? (((r + 0.055) / 1.055) ** 2.4) : (r / 12.92)
    g = g > 0.04045 ? (((g + 0.055) / 1.055) ** 2.4) : (g / 12.92)
    b = b > 0.04045 ? (((b + 0.055) / 1.055) ** 2.4) : (b / 12.92)

    const x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805)
    const y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722)
    const z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505)

    return [x * 100, y * 100, z * 100]
  }

  convert.rgb.lab = function (rgb) {
    const xyz = convert.rgb.xyz(rgb)
    let x = xyz[0]
    let y = xyz[1]
    let z = xyz[2]

    x /= 95.047
    y /= 100
    z /= 108.883

    x = x > 0.008856 ? (x ** (1 / 3)) : (7.787 * x) + (16 / 116)
    y = y > 0.008856 ? (y ** (1 / 3)) : (7.787 * y) + (16 / 116)
    z = z > 0.008856 ? (z ** (1 / 3)) : (7.787 * z) + (16 / 116)

    const l = (116 * y) - 16
    const a = 500 * (x - y)
    const b = 200 * (y - z)

    return [l, a, b]
  }

  convert.hsl.rgb = function (hsl) {
    const h = hsl[0] / 360
    const s = hsl[1] / 100
    const l = hsl[2] / 100
    let t2
    let t3
    let val

    if (s === 0) {
      val = l * 255
      return [val, val, val]
    }

    if (l < 0.5) {
      t2 = l * (1 + s)
    } else {
      t2 = l + s - l * s
    }

    const t1 = 2 * l - t2

    const rgb = [0, 0, 0]
    for (let i = 0; i < 3; i++) {
      t3 = h + 1 / 3 * -(i - 1)
      if (t3 < 0) {
        t3++
      }

      if (t3 > 1) {
        t3--
      }

      if (6 * t3 < 1) {
        val = t1 + (t2 - t1) * 6 * t3
      } else if (2 * t3 < 1) {
        val = t2
      } else if (3 * t3 < 2) {
        val = t1 + (t2 - t1) * (2 / 3 - t3) * 6
      } else {
        val = t1
      }

      rgb[i] = val * 255
    }

    return rgb
  }

  convert.hsl.hsv = function (hsl) {
    const h = hsl[0]
    let s = hsl[1] / 100
    let l = hsl[2] / 100
    let smin = s
    const lmin = Math.max(l, 0.01)

    l *= 2
    s *= (l <= 1) ? l : 2 - l
    smin *= lmin <= 1 ? lmin : 2 - lmin
    const v = (l + s) / 2
    const sv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s)

    return [h, sv * 100, v * 100]
  }

  convert.hsv.rgb = function (hsv) {
    const h = hsv[0] / 60
    const s = hsv[1] / 100
    let v = hsv[2] / 100
    const hi = Math.floor(h) % 6

    const f = h - Math.floor(h)
    const p = 255 * v * (1 - s)
    const q = 255 * v * (1 - (s * f))
    const t = 255 * v * (1 - (s * (1 - f)))
    v *= 255

    switch (hi) {
    case 0:
      return [v, t, p]
    case 1:
      return [q, v, p]
    case 2:
      return [p, v, t]
    case 3:
      return [p, q, v]
    case 4:
      return [t, p, v]
    case 5:
      return [v, p, q]
    }
  }

  convert.hsv.hsl = function (hsv) {
    const h = hsv[0]
    const s = hsv[1] / 100
    const v = hsv[2] / 100
    const vmin = Math.max(v, 0.01)
    let sl
    let l

    l = (2 - s) * v
    const lmin = (2 - s) * vmin
    sl = s * vmin
    sl /= (lmin <= 1) ? lmin : 2 - lmin
    sl = sl || 0
    l /= 2

    return [h, sl * 100, l * 100]
  }

  // http://dev.w3.org/csswg/css-color/#hwb-to-rgb
  convert.hwb.rgb = function (hwb) {
    const h = hwb[0] / 360
    let wh = hwb[1] / 100
    let bl = hwb[2] / 100
    const ratio = wh + bl
    let f

    // Wh + bl cant be > 1
    if (ratio > 1) {
      wh /= ratio
      bl /= ratio
    }

    const i = Math.floor(6 * h)
    const v = 1 - bl
    f = 6 * h - i

    if ((i & 0x01) !== 0) {
      f = 1 - f
    }

    const n = wh + f * (v - wh) // Linear interpolation

    let r
    let g
    let b
    /* eslint-disable max-statements-per-line,no-multi-spaces */
    switch (i) {
    default:
    case 6:
    case 0: r = v;  g = n;  b = wh; break
    case 1: r = n;  g = v;  b = wh; break
    case 2: r = wh; g = v;  b = n; break
    case 3: r = wh; g = n;  b = v; break
    case 4: r = n;  g = wh; b = v; break
    case 5: r = v;  g = wh; b = n; break
    }
    /* eslint-enable max-statements-per-line,no-multi-spaces */

    return [r * 255, g * 255, b * 255]
  }

  convert.cmyk.rgb = function (cmyk) {
    const c = cmyk[0] / 100
    const m = cmyk[1] / 100
    const y = cmyk[2] / 100
    const k = cmyk[3] / 100

    const r = 1 - Math.min(1, c * (1 - k) + k)
    const g = 1 - Math.min(1, m * (1 - k) + k)
    const b = 1 - Math.min(1, y * (1 - k) + k)

    return [r * 255, g * 255, b * 255]
  }

  convert.xyz.rgb = function (xyz) {
    const x = xyz[0] / 100
    const y = xyz[1] / 100
    const z = xyz[2] / 100
    let r
    let g
    let b

    r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986)
    g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415)
    b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570)

    // Assume sRGB
    r = r > 0.0031308
      ? ((1.055 * (r ** (1.0 / 2.4))) - 0.055)
      : r * 12.92

    g = g > 0.0031308
      ? ((1.055 * (g ** (1.0 / 2.4))) - 0.055)
      : g * 12.92

    b = b > 0.0031308
      ? ((1.055 * (b ** (1.0 / 2.4))) - 0.055)
      : b * 12.92

    r = Math.min(Math.max(0, r), 1)
    g = Math.min(Math.max(0, g), 1)
    b = Math.min(Math.max(0, b), 1)

    return [r * 255, g * 255, b * 255]
  }

  convert.xyz.lab = function (xyz) {
    let x = xyz[0]
    let y = xyz[1]
    let z = xyz[2]

    x /= 95.047
    y /= 100
    z /= 108.883

    x = x > 0.008856 ? (x ** (1 / 3)) : (7.787 * x) + (16 / 116)
    y = y > 0.008856 ? (y ** (1 / 3)) : (7.787 * y) + (16 / 116)
    z = z > 0.008856 ? (z ** (1 / 3)) : (7.787 * z) + (16 / 116)

    const l = (116 * y) - 16
    const a = 500 * (x - y)
    const b = 200 * (y - z)

    return [l, a, b]
  }

  convert.lab.xyz = function (lab) {
    const l = lab[0]
    const a = lab[1]
    const b = lab[2]
    let x
    let y
    let z

    y = (l + 16) / 116
    x = a / 500 + y
    z = y - b / 200

    const y2 = y ** 3
    const x2 = x ** 3
    const z2 = z ** 3
    y = y2 > 0.008856 ? y2 : (y - 16 / 116) / 7.787
    x = x2 > 0.008856 ? x2 : (x - 16 / 116) / 7.787
    z = z2 > 0.008856 ? z2 : (z - 16 / 116) / 7.787

    x *= 95.047
    y *= 100
    z *= 108.883

    return [x, y, z]
  }

  convert.lab.lch = function (lab) {
    const l = lab[0]
    const a = lab[1]
    const b = lab[2]
    let h

    const hr = Math.atan2(b, a)
    h = hr * 360 / 2 / Math.PI

    if (h < 0) {
      h += 360
    }

    const c = Math.sqrt(a * a + b * b)

    return [l, c, h]
  }

  convert.lch.lab = function (lch) {
    const l = lch[0]
    const c = lch[1]
    const h = lch[2]

    const hr = h / 360 * 2 * Math.PI
    const a = c * Math.cos(hr)
    const b = c * Math.sin(hr)

    return [l, a, b]
  }

  convert.rgb.ansi16 = function (args, saturation = null) {
    const [r, g, b] = args
    let value = saturation === null ? convert.rgb.hsv(args)[2] : saturation // Hsv -> ansi16 optimization

    value = Math.round(value / 50)

    if (value === 0) {
      return 30
    }

    let ansi = 30
        + ((Math.round(b / 255) << 2)
          | (Math.round(g / 255) << 1)
          | Math.round(r / 255))

    if (value === 2) {
      ansi += 60
    }

    return ansi
  }

  convert.hsv.ansi16 = function (args) {
    // Optimization here; we already know the value and don't need to get
    // it converted for us.
    return convert.rgb.ansi16(convert.hsv.rgb(args), args[2])
  }

  convert.rgb.ansi256 = function (args) {
    const r = args[0]
    const g = args[1]
    const b = args[2]

    // We use the extended greyscale palette here, with the exception of
    // black and white. normal palette only has 4 greyscale shades.
    if (r === g && g === b) {
      if (r < 8) {
        return 16
      }

      if (r > 248) {
        return 231
      }

      return Math.round(((r - 8) / 247) * 24) + 232
    }

    const ansi = 16
        + (36 * Math.round(r / 255 * 5))
        + (6 * Math.round(g / 255 * 5))
        + Math.round(b / 255 * 5)

    return ansi
  }

  convert.ansi16.rgb = function (args) {
    let color = args % 10

    // Handle greyscale
    if (color === 0 || color === 7) {
      if (args > 50) {
        color += 3.5
      }

      color = color / 10.5 * 255

      return [color, color, color]
    }

    const mult = (~~(args > 50) + 1) * 0.5
    const r = ((color & 1) * mult) * 255
    const g = (((color >> 1) & 1) * mult) * 255
    const b = (((color >> 2) & 1) * mult) * 255

    return [r, g, b]
  }

  convert.ansi256.rgb = function (args) {
    // Handle greyscale
    if (args >= 232) {
      const c = (args - 232) * 10 + 8
      return [c, c, c]
    }

    args -= 16

    let rem
    const r = Math.floor(args / 36) / 5 * 255
    const g = Math.floor((rem = args % 36) / 6) / 5 * 255
    const b = (rem % 6) / 5 * 255

    return [r, g, b]
  }

  convert.rgb.hex = function (args) {
    const integer = ((Math.round(args[0]) & 0xFF) << 16)
        + ((Math.round(args[1]) & 0xFF) << 8)
        + (Math.round(args[2]) & 0xFF)

    const string = integer.toString(16).toUpperCase()
    return '000000'.substring(string.length) + string
  }

  convert.hex.rgb = function (args) {
    const match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i)
    if (!match) {
      return [0, 0, 0]
    }

    let colorString = match[0]

    if (match[0].length === 3) {
      colorString = colorString.split('').map(char => {
        return char + char
      }).join('')
    }

    const integer = parseInt(colorString, 16)
    const r = (integer >> 16) & 0xFF
    const g = (integer >> 8) & 0xFF
    const b = integer & 0xFF

    return [r, g, b]
  }

  convert.rgb.hcg = function (rgb) {
    const r = rgb[0] / 255
    const g = rgb[1] / 255
    const b = rgb[2] / 255
    const max = Math.max(Math.max(r, g), b)
    const min = Math.min(Math.min(r, g), b)
    const chroma = (max - min)
    let grayscale
    let hue

    if (chroma < 1) {
      grayscale = min / (1 - chroma)
    } else {
      grayscale = 0
    }

    if (chroma <= 0) {
      hue = 0
    } else
    if (max === r) {
      hue = ((g - b) / chroma) % 6
    } else
    if (max === g) {
      hue = 2 + (b - r) / chroma
    } else {
      hue = 4 + (r - g) / chroma
    }

    hue /= 6
    hue %= 1

    return [hue * 360, chroma * 100, grayscale * 100]
  }

  convert.hsl.hcg = function (hsl) {
    const s = hsl[1] / 100
    const l = hsl[2] / 100

    const c = l < 0.5 ? (2.0 * s * l) : (2.0 * s * (1.0 - l))

    let f = 0
    if (c < 1.0) {
      f = (l - 0.5 * c) / (1.0 - c)
    }

    return [hsl[0], c * 100, f * 100]
  }

  convert.hsv.hcg = function (hsv) {
    const s = hsv[1] / 100
    const v = hsv[2] / 100

    const c = s * v
    let f = 0

    if (c < 1.0) {
      f = (v - c) / (1 - c)
    }

    return [hsv[0], c * 100, f * 100]
  }

  convert.hcg.rgb = function (hcg) {
    const h = hcg[0] / 360
    const c = hcg[1] / 100
    const g = hcg[2] / 100

    if (c === 0.0) {
      return [g * 255, g * 255, g * 255]
    }

    const pure = [0, 0, 0]
    const hi = (h % 1) * 6
    const v = hi % 1
    const w = 1 - v
    let mg = 0

    /* eslint-disable max-statements-per-line */
    switch (Math.floor(hi)) {
    case 0:
      pure[0] = 1; pure[1] = v; pure[2] = 0; break
    case 1:
      pure[0] = w; pure[1] = 1; pure[2] = 0; break
    case 2:
      pure[0] = 0; pure[1] = 1; pure[2] = v; break
    case 3:
      pure[0] = 0; pure[1] = w; pure[2] = 1; break
    case 4:
      pure[0] = v; pure[1] = 0; pure[2] = 1; break
    default:
      pure[0] = 1; pure[1] = 0; pure[2] = w
    }
    /* eslint-enable max-statements-per-line */

    mg = (1.0 - c) * g

    return [
      (c * pure[0] + mg) * 255,
      (c * pure[1] + mg) * 255,
      (c * pure[2] + mg) * 255
    ]
  }

  convert.hcg.hsv = function (hcg) {
    const c = hcg[1] / 100
    const g = hcg[2] / 100

    const v = c + g * (1.0 - c)
    let f = 0

    if (v > 0.0) {
      f = c / v
    }

    return [hcg[0], f * 100, v * 100]
  }

  convert.hcg.hsl = function (hcg) {
    const c = hcg[1] / 100
    const g = hcg[2] / 100

    const l = g * (1.0 - c) + 0.5 * c
    let s = 0

    if (l > 0.0 && l < 0.5) {
      s = c / (2 * l)
    } else
    if (l >= 0.5 && l < 1.0) {
      s = c / (2 * (1 - l))
    }

    return [hcg[0], s * 100, l * 100]
  }

  convert.hcg.hwb = function (hcg) {
    const c = hcg[1] / 100
    const g = hcg[2] / 100
    const v = c + g * (1.0 - c)
    return [hcg[0], (v - c) * 100, (1 - v) * 100]
  }

  convert.hwb.hcg = function (hwb) {
    const w = hwb[1] / 100
    const b = hwb[2] / 100
    const v = 1 - b
    const c = v - w
    let g = 0

    if (c < 1) {
      g = (v - c) / (1 - c)
    }

    return [hwb[0], c * 100, g * 100]
  }

  convert.apple.rgb = function (apple) {
    return [(apple[0] / 65535) * 255, (apple[1] / 65535) * 255, (apple[2] / 65535) * 255]
  }

  convert.rgb.apple = function (rgb) {
    return [(rgb[0] / 255) * 65535, (rgb[1] / 255) * 65535, (rgb[2] / 255) * 65535]
  }

  convert.gray.rgb = function (args) {
    return [args[0] / 100 * 255, args[0] / 100 * 255, args[0] / 100 * 255]
  }

  convert.gray.hsl = function (args) {
    return [0, 0, args[0]]
  }

  convert.gray.hsv = convert.gray.hsl

  convert.gray.hwb = function (gray) {
    return [0, 100, gray[0]]
  }

  convert.gray.cmyk = function (gray) {
    return [0, 0, 0, gray[0]]
  }

  convert.gray.lab = function (gray) {
    return [gray[0], 0, 0]
  }

  convert.gray.hex = function (gray) {
    const val = Math.round(gray[0] / 100 * 255) & 0xFF
    const integer = (val << 16) + (val << 8) + val

    const string = integer.toString(16).toUpperCase()
    return '000000'.substring(string.length) + string
  }

  convert.rgb.gray = function (rgb) {
    const val = (rgb[0] + rgb[1] + rgb[2]) / 3
    return [val / 255 * 100]
  }

},{'color-name':4}],2:[function(require,module,exports){
  const conversions = require('./conversions')
  const route = require('./route')

  const convert = {}

  const models = Object.keys(conversions)

  function wrapRaw(fn) {
    const wrappedFn = function (...args) {
      const arg0 = args[0]
      if (arg0 === undefined || arg0 === null) {
        return arg0
      }

      if (arg0.length > 1) {
        args = arg0
      }

      return fn(args)
    }

    // Preserve .conversion property if there is one
    if ('conversion' in fn) {
      wrappedFn.conversion = fn.conversion
    }

    return wrappedFn
  }

  function wrapRounded(fn) {
    const wrappedFn = function (...args) {
      const arg0 = args[0]

      if (arg0 === undefined || arg0 === null) {
        return arg0
      }

      if (arg0.length > 1) {
        args = arg0
      }

      const result = fn(args)

      // We're assuming the result is an array here.
      // see notice in conversions.js; don't use box types
      // in conversion functions.
      if (typeof result === 'object') {
        for (let len = result.length, i = 0; i < len; i++) {
          result[i] = Math.round(result[i])
        }
      }

      return result
    }

    // Preserve .conversion property if there is one
    if ('conversion' in fn) {
      wrappedFn.conversion = fn.conversion
    }

    return wrappedFn
  }

  models.forEach(fromModel => {
    convert[fromModel] = {}

    Object.defineProperty(convert[fromModel], 'channels', {value: conversions[fromModel].channels})
    Object.defineProperty(convert[fromModel], 'labels', {value: conversions[fromModel].labels})

    const routes = route(fromModel)
    const routeModels = Object.keys(routes)

    routeModels.forEach(toModel => {
      const fn = routes[toModel]

      convert[fromModel][toModel] = wrapRounded(fn)
      convert[fromModel][toModel].raw = wrapRaw(fn)
    })
  })

  module.exports = convert

},{'./conversions':1,'./route':3}],3:[function(require,module,exports){
  const conversions = require('./conversions')

  /*
      This function routes a model to all other models.

      all functions that are routed have a property `.conversion` attached
      to the returned synthetic function. This property is an array
      of strings, each with the steps in between the 'from' and 'to'
      color models (inclusive).

      conversions that are not possible simply are not included.
    */

  function buildGraph() {
    const graph = {}
    // https://jsperf.com/object-keys-vs-for-in-with-closure/3
    const models = Object.keys(conversions)

    for (let len = models.length, i = 0; i < len; i++) {
      graph[models[i]] = {
        // http://jsperf.com/1-vs-infinity
        // micro-opt, but this is simple.
        distance: -1,
        parent: null
      }
    }

    return graph
  }

  // https://en.wikipedia.org/wiki/Breadth-first_search
  function deriveBFS(fromModel) {
    const graph = buildGraph()
    const queue = [fromModel] // Unshift -> queue -> pop

    graph[fromModel].distance = 0

    while (queue.length) {
      const current = queue.pop()
      const adjacents = Object.keys(conversions[current])

      for (let len = adjacents.length, i = 0; i < len; i++) {
        const adjacent = adjacents[i]
        const node = graph[adjacent]

        if (node.distance === -1) {
          node.distance = graph[current].distance + 1
          node.parent = current
          queue.unshift(adjacent)
        }
      }
    }

    return graph
  }

  function link(from, to) {
    return function (args) {
      return to(from(args))
    }
  }

  function wrapConversion(toModel, graph) {
    const path = [graph[toModel].parent, toModel]
    let fn = conversions[graph[toModel].parent][toModel]

    let cur = graph[toModel].parent
    while (graph[cur].parent) {
      path.unshift(graph[cur].parent)
      fn = link(conversions[graph[cur].parent][cur], fn)
      cur = graph[cur].parent
    }

    fn.conversion = path
    return fn
  }

  module.exports = function (fromModel) {
    const graph = deriveBFS(fromModel)
    const conversion = {}

    const models = Object.keys(graph)
    for (let len = models.length, i = 0; i < len; i++) {
      const toModel = models[i]
      const node = graph[toModel]

      if (node.parent === null) {
        // No possible conversion, or this node is the source model.
        continue
      }

      conversion[toModel] = wrapConversion(toModel, graph)
    }

    return conversion
  }


},{'./conversions':1}],4:[function(require,module,exports){
  'use strict'

  module.exports = {
    'aliceblue': [240, 248, 255],
    'antiquewhite': [250, 235, 215],
    'aqua': [0, 255, 255],
    'aquamarine': [127, 255, 212],
    'azure': [240, 255, 255],
    'beige': [245, 245, 220],
    'bisque': [255, 228, 196],
    'black': [0, 0, 0],
    'blanchedalmond': [255, 235, 205],
    'blue': [0, 0, 255],
    'blueviolet': [138, 43, 226],
    'brown': [165, 42, 42],
    'burlywood': [222, 184, 135],
    'cadetblue': [95, 158, 160],
    'chartreuse': [127, 255, 0],
    'chocolate': [210, 105, 30],
    'coral': [255, 127, 80],
    'cornflowerblue': [100, 149, 237],
    'cornsilk': [255, 248, 220],
    'crimson': [220, 20, 60],
    'cyan': [0, 255, 255],
    'darkblue': [0, 0, 139],
    'darkcyan': [0, 139, 139],
    'darkgoldenrod': [184, 134, 11],
    'darkgray': [169, 169, 169],
    'darkgreen': [0, 100, 0],
    'darkgrey': [169, 169, 169],
    'darkkhaki': [189, 183, 107],
    'darkmagenta': [139, 0, 139],
    'darkolivegreen': [85, 107, 47],
    'darkorange': [255, 140, 0],
    'darkorchid': [153, 50, 204],
    'darkred': [139, 0, 0],
    'darksalmon': [233, 150, 122],
    'darkseagreen': [143, 188, 143],
    'darkslateblue': [72, 61, 139],
    'darkslategray': [47, 79, 79],
    'darkslategrey': [47, 79, 79],
    'darkturquoise': [0, 206, 209],
    'darkviolet': [148, 0, 211],
    'deeppink': [255, 20, 147],
    'deepskyblue': [0, 191, 255],
    'dimgray': [105, 105, 105],
    'dimgrey': [105, 105, 105],
    'dodgerblue': [30, 144, 255],
    'firebrick': [178, 34, 34],
    'floralwhite': [255, 250, 240],
    'forestgreen': [34, 139, 34],
    'fuchsia': [255, 0, 255],
    'gainsboro': [220, 220, 220],
    'ghostwhite': [248, 248, 255],
    'gold': [255, 215, 0],
    'goldenrod': [218, 165, 32],
    'gray': [128, 128, 128],
    'green': [0, 128, 0],
    'greenyellow': [173, 255, 47],
    'grey': [128, 128, 128],
    'honeydew': [240, 255, 240],
    'hotpink': [255, 105, 180],
    'indianred': [205, 92, 92],
    'indigo': [75, 0, 130],
    'ivory': [255, 255, 240],
    'khaki': [240, 230, 140],
    'lavender': [230, 230, 250],
    'lavenderblush': [255, 240, 245],
    'lawngreen': [124, 252, 0],
    'lemonchiffon': [255, 250, 205],
    'lightblue': [173, 216, 230],
    'lightcoral': [240, 128, 128],
    'lightcyan': [224, 255, 255],
    'lightgoldenrodyellow': [250, 250, 210],
    'lightgray': [211, 211, 211],
    'lightgreen': [144, 238, 144],
    'lightgrey': [211, 211, 211],
    'lightpink': [255, 182, 193],
    'lightsalmon': [255, 160, 122],
    'lightseagreen': [32, 178, 170],
    'lightskyblue': [135, 206, 250],
    'lightslategray': [119, 136, 153],
    'lightslategrey': [119, 136, 153],
    'lightsteelblue': [176, 196, 222],
    'lightyellow': [255, 255, 224],
    'lime': [0, 255, 0],
    'limegreen': [50, 205, 50],
    'linen': [250, 240, 230],
    'magenta': [255, 0, 255],
    'maroon': [128, 0, 0],
    'mediumaquamarine': [102, 205, 170],
    'mediumblue': [0, 0, 205],
    'mediumorchid': [186, 85, 211],
    'mediumpurple': [147, 112, 219],
    'mediumseagreen': [60, 179, 113],
    'mediumslateblue': [123, 104, 238],
    'mediumspringgreen': [0, 250, 154],
    'mediumturquoise': [72, 209, 204],
    'mediumvioletred': [199, 21, 133],
    'midnightblue': [25, 25, 112],
    'mintcream': [245, 255, 250],
    'mistyrose': [255, 228, 225],
    'moccasin': [255, 228, 181],
    'navajowhite': [255, 222, 173],
    'navy': [0, 0, 128],
    'oldlace': [253, 245, 230],
    'olive': [128, 128, 0],
    'olivedrab': [107, 142, 35],
    'orange': [255, 165, 0],
    'orangered': [255, 69, 0],
    'orchid': [218, 112, 214],
    'palegoldenrod': [238, 232, 170],
    'palegreen': [152, 251, 152],
    'paleturquoise': [175, 238, 238],
    'palevioletred': [219, 112, 147],
    'papayawhip': [255, 239, 213],
    'peachpuff': [255, 218, 185],
    'peru': [205, 133, 63],
    'pink': [255, 192, 203],
    'plum': [221, 160, 221],
    'powderblue': [176, 224, 230],
    'purple': [128, 0, 128],
    'rebeccapurple': [102, 51, 153],
    'red': [255, 0, 0],
    'rosybrown': [188, 143, 143],
    'royalblue': [65, 105, 225],
    'saddlebrown': [139, 69, 19],
    'salmon': [250, 128, 114],
    'sandybrown': [244, 164, 96],
    'seagreen': [46, 139, 87],
    'seashell': [255, 245, 238],
    'sienna': [160, 82, 45],
    'silver': [192, 192, 192],
    'skyblue': [135, 206, 235],
    'slateblue': [106, 90, 205],
    'slategray': [112, 128, 144],
    'slategrey': [112, 128, 144],
    'snow': [255, 250, 250],
    'springgreen': [0, 255, 127],
    'steelblue': [70, 130, 180],
    'tan': [210, 180, 140],
    'teal': [0, 128, 128],
    'thistle': [216, 191, 216],
    'tomato': [255, 99, 71],
    'turquoise': [64, 224, 208],
    'violet': [238, 130, 238],
    'wheat': [245, 222, 179],
    'white': [255, 255, 255],
    'whitesmoke': [245, 245, 245],
    'yellow': [255, 255, 0],
    'yellowgreen': [154, 205, 50]
  }

},{}],5:[function(require,module,exports){
  /* MIT license */
  let colorNames = require('color-name')
  let swizzle = require('simple-swizzle')

  let reverseNames = {}

  // create a list of reverse color names
  for (let name in colorNames) {
    if (colorNames.hasOwnProperty(name)) {
      reverseNames[colorNames[name]] = name
    }
  }

  let cs = module.exports = {
    to: {},
    get: {}
  }

  cs.get = function (string) {
    let prefix = string.substring(0, 3).toLowerCase()
    let val
    let model
    switch (prefix) {
    case 'hsl':
      val = cs.get.hsl(string)
      model = 'hsl'
      break
    case 'hwb':
      val = cs.get.hwb(string)
      model = 'hwb'
      break
    default:
      val = cs.get.rgb(string)
      model = 'rgb'
      break
    }

    if (!val) {
      return null
    }

    return {model: model, value: val}
  }

  cs.get.rgb = function (string) {
    if (!string) {
      return null
    }

    let abbr = /^#([a-f0-9]{3,4})$/i
    let hex = /^#([a-f0-9]{6})([a-f0-9]{2})?$/i
    let rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/
    let per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/
    let keyword = /(\D+)/

    let rgb = [0, 0, 0, 1]
    let match
    let i
    let hexAlpha

    if (match = string.match(hex)) {
      hexAlpha = match[2]
      match = match[1]

      for (i = 0; i < 3; i++) {
        // https://jsperf.com/slice-vs-substr-vs-substring-methods-long-string/19
        let i2 = i * 2
        rgb[i] = parseInt(match.slice(i2, i2 + 2), 16)
      }

      if (hexAlpha) {
        rgb[3] = Math.round((parseInt(hexAlpha, 16) / 255) * 100) / 100
      }
    } else if (match = string.match(abbr)) {
      match = match[1]
      hexAlpha = match[3]

      for (i = 0; i < 3; i++) {
        rgb[i] = parseInt(match[i] + match[i], 16)
      }

      if (hexAlpha) {
        rgb[3] = Math.round((parseInt(hexAlpha + hexAlpha, 16) / 255) * 100) / 100
      }
    } else if (match = string.match(rgba)) {
      for (i = 0; i < 3; i++) {
        rgb[i] = parseInt(match[i + 1], 0)
      }

      if (match[4]) {
        rgb[3] = parseFloat(match[4])
      }
    } else if (match = string.match(per)) {
      for (i = 0; i < 3; i++) {
        rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55)
      }

      if (match[4]) {
        rgb[3] = parseFloat(match[4])
      }
    } else if (match = string.match(keyword)) {
      if (match[1] === 'transparent') {
        return [0, 0, 0, 0]
      }

      rgb = colorNames[match[1]]

      if (!rgb) {
        return null
      }

      rgb[3] = 1

      return rgb
    } else {
      return null
    }

    for (i = 0; i < 3; i++) {
      rgb[i] = clamp(rgb[i], 0, 255)
    }
    rgb[3] = clamp(rgb[3], 0, 1)

    return rgb
  }

  cs.get.hsl = function (string) {
    if (!string) {
      return null
    }

    let hsl = /^hsla?\(\s*([+-]?(?:\d*\.)?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/
    let match = string.match(hsl)

    if (match) {
      let alpha = parseFloat(match[4])
      let h = (parseFloat(match[1]) + 360) % 360
      let s = clamp(parseFloat(match[2]), 0, 100)
      let l = clamp(parseFloat(match[3]), 0, 100)
      let a = clamp(isNaN(alpha) ? 1 : alpha, 0, 1)

      return [h, s, l, a]
    }

    return null
  }

  cs.get.hwb = function (string) {
    if (!string) {
      return null
    }

    let hwb = /^hwb\(\s*([+-]?\d*[\.]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/
    let match = string.match(hwb)

    if (match) {
      let alpha = parseFloat(match[4])
      let h = ((parseFloat(match[1]) % 360) + 360) % 360
      let w = clamp(parseFloat(match[2]), 0, 100)
      let b = clamp(parseFloat(match[3]), 0, 100)
      let a = clamp(isNaN(alpha) ? 1 : alpha, 0, 1)
      return [h, w, b, a]
    }

    return null
  }

  cs.to.hex = function () {
    let rgba = swizzle(arguments)

    return (
      '#' +
        hexDouble(rgba[0]) +
        hexDouble(rgba[1]) +
        hexDouble(rgba[2]) +
        (rgba[3] < 1
          ? (hexDouble(Math.round(rgba[3] * 255)))
          : '')
    )
  }

  cs.to.rgb = function () {
    let rgba = swizzle(arguments)

    return rgba.length < 4 || rgba[3] === 1
      ? 'rgb(' + Math.round(rgba[0]) + ', ' + Math.round(rgba[1]) + ', ' + Math.round(rgba[2]) + ')'
      : 'rgba(' + Math.round(rgba[0]) + ', ' + Math.round(rgba[1]) + ', ' + Math.round(rgba[2]) + ', ' + rgba[3] + ')'
  }

  cs.to.rgb.percent = function () {
    let rgba = swizzle(arguments)

    let r = Math.round(rgba[0] / 255 * 100)
    let g = Math.round(rgba[1] / 255 * 100)
    let b = Math.round(rgba[2] / 255 * 100)

    return rgba.length < 4 || rgba[3] === 1
      ? 'rgb(' + r + '%, ' + g + '%, ' + b + '%)'
      : 'rgba(' + r + '%, ' + g + '%, ' + b + '%, ' + rgba[3] + ')'
  }

  cs.to.hsl = function () {
    let hsla = swizzle(arguments)
    return hsla.length < 4 || hsla[3] === 1
      ? 'hsl(' + hsla[0] + ', ' + hsla[1] + '%, ' + hsla[2] + '%)'
      : 'hsla(' + hsla[0] + ', ' + hsla[1] + '%, ' + hsla[2] + '%, ' + hsla[3] + ')'
  }

  // hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax
  // (hwb have alpha optional & 1 is default value)
  cs.to.hwb = function () {
    let hwba = swizzle(arguments)

    let a = ''
    if (hwba.length >= 4 && hwba[3] !== 1) {
      a = ', ' + hwba[3]
    }

    return 'hwb(' + hwba[0] + ', ' + hwba[1] + '%, ' + hwba[2] + '%' + a + ')'
  }

  cs.to.keyword = function (rgb) {
    return reverseNames[rgb.slice(0, 3)]
  }

  // helpers
  function clamp(num, min, max) {
    return Math.min(Math.max(min, num), max)
  }

  function hexDouble(num) {
    let str = num.toString(16).toUpperCase()
    return (str.length < 2) ? '0' + str : str
  }

},{'color-name':4,'simple-swizzle':7}],6:[function(require,module,exports){
  module.exports = function isArrayish(obj) {
    if (!obj || typeof obj === 'string') {
      return false
    }

    return obj instanceof Array || Array.isArray(obj) ||
        (obj.length >= 0 && (obj.splice instanceof Function ||
          (Object.getOwnPropertyDescriptor(obj, (obj.length - 1)) && obj.constructor.name !== 'String')))
  }

},{}],7:[function(require,module,exports){
  'use strict'

  let isArrayish = require('is-arrayish')

  let concat = Array.prototype.concat
  let slice = Array.prototype.slice

  let swizzle = module.exports = function swizzle(args) {
    let results = []

    for (let i = 0, len = args.length; i < len; i++) {
      let arg = args[i]

      if (isArrayish(arg)) {
        // http://jsperf.com/javascript-array-concat-vs-push/98
        results = concat.call(results, slice.call(arg))
      } else {
        results.push(arg)
      }
    }

    return results
  }

  swizzle.wrap = function (fn) {
    return function () {
      return fn(swizzle(arguments))
    }
  }

},{'is-arrayish':6}],8:[function(require,module,exports){
  'use strict'

  let colorString = require('color-string')
  let convert = require('color-convert')

  let _slice = [].slice

  let skippedModels = [
    // to be honest, I don't really feel like keyword belongs in color convert, but eh.
    'keyword',

    // gray conflicts with some method names, and has its own method defined.
    'gray',

    // shouldn't really be in color-convert either...
    'hex'
  ]

  let hashedModelKeys = {}
  Object.keys(convert).forEach(function(model) {
    hashedModelKeys[_slice.call(convert[model].labels).sort().join('')] = model
  })

  let limiters = {}

  function Color(obj, model) {
    if (!(this instanceof Color)) {
      return new Color(obj, model)
    }

    if (model && model in skippedModels) {
      model = null
    }

    if (model && !(model in convert)) {
      throw new Error('Unknown model: ' + model)
    }

    let i
    let channels

    if (obj == null) { // eslint-disable-line no-eq-null,eqeqeq
      this.model = 'rgb'
      this.color = [0, 0, 0]
      this.valpha = 1
    } else if (obj instanceof Color) {
      this.model = obj.model
      this.color = obj.color.slice()
      this.valpha = obj.valpha
    } else if (typeof obj === 'string') {
      let result = colorString.get(obj)
      if (result === null) {
        throw new Error('Unable to parse color from string: ' + obj)
      }

      this.model = result.model
      channels = convert[this.model].channels
      this.color = result.value.slice(0, channels)
      this.valpha = typeof result.value[channels] === 'number' ? result.value[channels] : 1
    } else if (obj.length) {
      this.model = model || 'rgb'
      channels = convert[this.model].channels
      let newArr = _slice.call(obj, 0, channels)
      this.color = zeroArray(newArr, channels)
      this.valpha = typeof obj[channels] === 'number' ? obj[channels] : 1
    } else if (typeof obj === 'number') {
      // this is always RGB - can be converted later on.
      obj &= 0xFFFFFF
      this.model = 'rgb'
      this.color = [
        (obj >> 16) & 0xFF,
        (obj >> 8) & 0xFF,
        obj & 0xFF
      ]
      this.valpha = 1
    } else {
      this.valpha = 1

      let keys = Object.keys(obj)
      if ('alpha' in obj) {
        keys.splice(keys.indexOf('alpha'), 1)
        this.valpha = typeof obj.alpha === 'number' ? obj.alpha : 0
      }

      let hashedKeys = keys.sort().join('')
      if (!(hashedKeys in hashedModelKeys)) {
        throw new Error('Unable to parse color from object: ' + JSON.stringify(obj))
      }

      this.model = hashedModelKeys[hashedKeys]

      let labels = convert[this.model].labels
      let color = []
      for (i = 0; i < labels.length; i++) {
        color.push(obj[labels[i]])
      }

      this.color = zeroArray(color)
    }

    // perform limitations (clamping, etc.)
    if (limiters[this.model]) {
      channels = convert[this.model].channels
      for (i = 0; i < channels; i++) {
        let limit = limiters[this.model][i]
        if (limit) {
          this.color[i] = limit(this.color[i])
        }
      }
    }

    this.valpha = Math.max(0, Math.min(1, this.valpha))

    if (Object.freeze) {
      Object.freeze(this)
    }
  }

  Color.prototype = {
    toString: function() {
      return this.string()
    },

    toJSON: function() {
      return this[this.model]()
    },

    string: function(places) {
      let self = this.model in colorString.to ? this : this.rgb()
      self = self.round(typeof places === 'number' ? places : 1)
      let args = self.valpha === 1 ? self.color : self.color.concat(this.valpha)
      return colorString.to[self.model](args)
    },

    percentString: function(places) {
      let self = this.rgb().round(typeof places === 'number' ? places : 1)
      let args = self.valpha === 1 ? self.color : self.color.concat(this.valpha)
      return colorString.to.rgb.percent(args)
    },

    array: function() {
      return this.valpha === 1 ? this.color.slice() : this.color.concat(this.valpha)
    },

    object: function() {
      let result = {}
      let channels = convert[this.model].channels
      let labels = convert[this.model].labels

      for (let i = 0; i < channels; i++) {
        result[labels[i]] = this.color[i]
      }

      if (this.valpha !== 1) {
        result.alpha = this.valpha
      }

      return result
    },

    unitArray: function() {
      let rgb = this.rgb().color
      rgb[0] /= 255
      rgb[1] /= 255
      rgb[2] /= 255

      if (this.valpha !== 1) {
        rgb.push(this.valpha)
      }

      return rgb
    },

    unitObject: function() {
      let rgb = this.rgb().object()
      rgb.r /= 255
      rgb.g /= 255
      rgb.b /= 255

      if (this.valpha !== 1) {
        rgb.alpha = this.valpha
      }

      return rgb
    },

    round: function(places) {
      places = Math.max(places || 0, 0)
      return new Color(this.color.map(roundToPlace(places)).concat(this.valpha), this.model)
    },

    alpha: function(val) {
      if (arguments.length) {
        return new Color(this.color.concat(Math.max(0, Math.min(1, val))), this.model)
      }

      return this.valpha
    },

    // rgb
    red: getset('rgb', 0, maxfn(255)),
    green: getset('rgb', 1, maxfn(255)),
    blue: getset('rgb', 2, maxfn(255)),

    hue: getset(['hsl', 'hsv', 'hsl', 'hwb', 'hcg'], 0, function(val) { return ((val % 360) + 360) % 360 }), // eslint-disable-line brace-style

    saturationl: getset('hsl', 1, maxfn(100)),
    lightness: getset('hsl', 2, maxfn(100)),

    saturationv: getset('hsv', 1, maxfn(100)),
    value: getset('hsv', 2, maxfn(100)),

    chroma: getset('hcg', 1, maxfn(100)),
    gray: getset('hcg', 2, maxfn(100)),

    white: getset('hwb', 1, maxfn(100)),
    wblack: getset('hwb', 2, maxfn(100)),

    cyan: getset('cmyk', 0, maxfn(100)),
    magenta: getset('cmyk', 1, maxfn(100)),
    yellow: getset('cmyk', 2, maxfn(100)),
    black: getset('cmyk', 3, maxfn(100)),

    x: getset('xyz', 0, maxfn(100)),
    y: getset('xyz', 1, maxfn(100)),
    z: getset('xyz', 2, maxfn(100)),

    l: getset('lab', 0, maxfn(100)),
    a: getset('lab', 1),
    b: getset('lab', 2),

    keyword: function(val) {
      if (arguments.length) {
        return new Color(val)
      }

      return convert[this.model].keyword(this.color)
    },

    hex: function(val) {
      if (arguments.length) {
        return new Color(val)
      }

      return colorString.to.hex(this.rgb().round().color)
    },

    rgbNumber: function() {
      let rgb = this.rgb().color
      return ((rgb[0] & 0xFF) << 16) | ((rgb[1] & 0xFF) << 8) | (rgb[2] & 0xFF)
    },

    luminosity: function() {
      // http://www.w3.org/TR/WCAG20/#relativeluminancedef
      let rgb = this.rgb().color

      let lum = []
      for (let i = 0; i < rgb.length; i++) {
        let chan = rgb[i] / 255
        lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4)
      }

      return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2]
    },

    contrast: function(color2) {
      // http://www.w3.org/TR/WCAG20/#contrast-ratiodef
      let lum1 = this.luminosity()
      let lum2 = color2.luminosity()

      if (lum1 > lum2) {
        return (lum1 + 0.05) / (lum2 + 0.05)
      }

      return (lum2 + 0.05) / (lum1 + 0.05)
    },

    level: function(color2) {
      let contrastRatio = this.contrast(color2)
      if (contrastRatio >= 7.1) {
        return 'AAA'
      }

      return (contrastRatio >= 4.5) ? 'AA' : ''
    },

    isDark: function() {
      // YIQ equation from http://24ways.org/2010/calculating-color-contrast
      let rgb = this.rgb().color
      let yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000
      return yiq < 128
    },

    isLight: function() {
      return !this.isDark()
    },

    negate: function() {
      let rgb = this.rgb()
      for (let i = 0; i < 3; i++) {
        rgb.color[i] = 255 - rgb.color[i]
      }
      return rgb
    },

    lighten: function(ratio) {
      let hsl = this.hsl()
      hsl.color[2] += hsl.color[2] * ratio
      return hsl
    },

    darken: function(ratio) {
      let hsl = this.hsl()
      hsl.color[2] -= hsl.color[2] * ratio
      return hsl
    },

    saturate: function(ratio) {
      let hsl = this.hsl()
      hsl.color[1] += hsl.color[1] * ratio
      return hsl
    },

    desaturate: function(ratio) {
      let hsl = this.hsl()
      hsl.color[1] -= hsl.color[1] * ratio
      return hsl
    },

    whiten: function(ratio) {
      let hwb = this.hwb()
      hwb.color[1] += hwb.color[1] * ratio
      return hwb
    },

    blacken: function(ratio) {
      let hwb = this.hwb()
      hwb.color[2] += hwb.color[2] * ratio
      return hwb
    },

    grayscale: function() {
      // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
      let rgb = this.rgb().color
      let val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11
      return Color.rgb(val, val, val)
    },

    fade: function(ratio) {
      return this.alpha(this.valpha - (this.valpha * ratio))
    },

    opaquer: function(ratio) {
      return this.alpha(this.valpha + (this.valpha * ratio))
    },

    rotate: function(degrees) {
      let hsl = this.hsl()
      let hue = hsl.color[0]
      hue = (hue + degrees) % 360
      hue = hue < 0 ? 360 + hue : hue
      hsl.color[0] = hue
      return hsl
    },

    mix: function(mixinColor, weight) {
      // ported from sass implementation in C
      // https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209
      if (!mixinColor || !mixinColor.rgb) {
        throw new Error('Argument to "mix" was not a Color instance, but rather an instance of ' + typeof mixinColor)
      }
      let color1 = mixinColor.rgb()
      let color2 = this.rgb()
      let p = weight === undefined ? 0.5 : weight

      let w = 2 * p - 1
      let a = color1.alpha() - color2.alpha()

      let w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0
      let w2 = 1 - w1

      return Color.rgb(
        w1 * color1.red() + w2 * color2.red(),
        w1 * color1.green() + w2 * color2.green(),
        w1 * color1.blue() + w2 * color2.blue(),
        color1.alpha() * p + color2.alpha() * (1 - p))
    }
  }

  // model conversion methods and static constructors
  Object.keys(convert).forEach(function(model) {
    if (skippedModels.indexOf(model) !== -1) {
      return
    }

    let channels = convert[model].channels

    // conversion methods
    Color.prototype[model] = function() {
      if (this.model === model) {
        return new Color(this)
      }

      if (arguments.length) {
        return new Color(arguments, model)
      }

      let newAlpha = typeof arguments[channels] === 'number' ? channels : this.valpha
      return new Color(assertArray(convert[this.model][model].raw(this.color)).concat(newAlpha), model)
    }

    // 'static' construction methods
    Color[model] = function(color) {
      if (typeof color === 'number') {
        color = zeroArray(_slice.call(arguments), channels)
      }
      return new Color(color, model)
    }
  })

  function roundTo(num, places) {
    return Number(num.toFixed(places))
  }

  function roundToPlace(places) {
    return function(num) {
      return roundTo(num, places)
    }
  }

  function getset(model, channel, modifier) {
    model = Array.isArray(model) ? model : [model]

    model.forEach(function(m) {
      (limiters[m] || (limiters[m] = []))[channel] = modifier
    })

    model = model[0]

    return function(val) {
      let result

      if (arguments.length) {
        if (modifier) {
          val = modifier(val)
        }

        result = this[model]()
        result.color[channel] = val
        return result
      }

      result = this[model]().color[channel]
      if (modifier) {
        result = modifier(result)
      }

      return result
    }
  }

  function maxfn(max) {
    return function(v) {
      return Math.max(0, Math.min(max, v))
    }
  }

  function assertArray(val) {
    return Array.isArray(val) ? val : [val]
  }

  function zeroArray(arr, length) {
    for (let i = 0; i < length; i++) {
      if (typeof arr[i] !== 'number') {
        arr[i] = 0
      }
    }

    return arr
  }

  window.Color = Color
},{'color-convert':2,'color-string':5}]},{},[8])
